package xyz.ibenben.zhongdian.common.shiro;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import xyz.ibenben.zhongdian.common.exception.ExceptionEnum;
import xyz.ibenben.zhongdian.common.exception.MyException;
import xyz.ibenben.zhongdian.common.job.NewJob;
import xyz.ibenben.zhongdian.common.job.QuartzManager;
import xyz.ibenben.zhongdian.common.redis.ShiroCache;
import xyz.ibenben.zhongdian.common.util.DateUtils;
import xyz.ibenben.zhongdian.system.entity.sys.SysUser;
import xyz.ibenben.zhongdian.system.service.sys.SysUserService;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 限制登录出错类
 * 限制登录次数，如果5次出错，锁定1个小时
 * 1小时后需要通过管理员解除限制，这里可以考虑使用定时任务来处理数据
 *
 * @author chenjian
 * @since 2017年10月18日下午5:17:22
 */
public class LimitRetryHashedMatcher extends HashedCredentialsMatcher {
	@Autowired
	private SysUserService sysUserService;
	@Autowired
    private RedisTemplate redisTemplate;

	/**
	 * 匹配
	 * @param token 参数
	 * @param info 参数
	 * @return 返回值
	 */
	@Override 
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { 
		String username = (String) token.getPrincipal();
		ShiroCache<String, Object> shiroCache = new ShiroCache<>("passwordRetry", redisTemplate);
		//retrycount + 1
		Object element = shiroCache.get(username);
		if (element == null) {
            shiroCache.put(username, 1);
			element = 0;
		}else{ 
			element = Integer.parseInt(element.toString()) + 1;
            shiroCache.put(username,element);
		} 
		AtomicInteger retryCount = new AtomicInteger(Integer.parseInt(element.toString()));
		//重试5次后不对，限制用户登录
		if (retryCount.incrementAndGet() > 5) { 
			//if retrycount >5 throw
			SysUser user = sysUserService.selectByUsername(username);
			user.setEnable(0);
			sysUserService.updateAll(user, null);
			Map<String, Object> map = new HashMap<>();
			map.put("sysUserService", sysUserService);
			map.put("userId", user.getId());
            Date date = DateUtils.setHourNew(new Date(), +1);
            //一小时后执行把数据从数据库中更新为可用
			QuartzManager.addJob("jobLimit", NewJob.class, DateUtils.translation(date), map);
			//在同一异常管理中抛出此异常，并处理该用户
			throw new MyException(ExceptionEnum.PROCESSUSERLIMITEXCEPTION, new ExcessiveAttemptsException(), user.getId());
		}
		boolean matches = super.doCredentialsMatch(token, info); 
		if (matches) { 
			//清除重试次数
            shiroCache.remove(username);
		}else{
		    //重新匹配
			info.getCredentials();
			matches = super.doCredentialsMatch(token, info);
		}
		return matches; 
	} 
}
